/******************************************************
 * @file bmp.c
 * @author Destiny 
 * @brief bmp格式图片处理
 * 
 * @version 0.1
 * @date 2024-07-18
 *****************************************************/
#include <config.h>
#include <pic_operation.h>
#include <picfmt_manager.h>
#include <file.h>
#include <stdlib.h>
#include <string.h>

/* BMP位图文件头 */
typedef struct tagBITMAPFILEHEADER { 
	uint16_t bfType;      // 位图文件的类型，必须为BMP (2个字节)
	unsigned long  bfSize;      // 位图文件的大小，以字节为单位 (4个字节)
	uint16_t bfReserved1; // 位图文件保留字，必须为0 (2个字节)
	uint16_t bfReserved2; // 位图文件保留字，必须为0 (2个字节)
	unsigned long  bfOffBits;   // 位图数据的起始位置，以相对于位图 (4个字节)
}  __attribute__ ((packed)) BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER { 
	unsigned long  biSize;   			// 本结构所占用字节数  (4个字节)
	unsigned long  biWidth;				// 位图的宽度，以像素为单位(4个字节)
	unsigned long  biHeight;			// 位图的高度，以像素为单位(4个字节)
	uint16_t biPlanes;			// 目标设备的级别，必须为1(2个字节)
	uint16_t biBitCount;			// 每个像素所需的位数，必须是1(双色)、4(16色)、8(256色)、24(真彩色)或32(增强真彩色)之一 (2个字节)
	unsigned long  biCompression;;		// 位图压缩类型，必须是 0(不压缩)、 1(BI_RLE8 压缩类型)或2(BI_RLE4压缩类型)之一 ) (4个字节)
	unsigned long  biSizeImage;			// 位图的大小，以字节为单位(4个字节)
	unsigned long  biXPelsPerMeteer;	// 位图水平分辨率，每米像素数(4个字节)
	unsigned long  biYPelsPerMeteer;	// 位图垂直分辨率，每米像素数(4个字节)
	unsigned long  biClrUsed;			// 位图实际使用的颜色表中的颜色数(4个字节)
	unsigned long  biClrImportant;		// 位图显示过程中重要的颜色数(4个字节)
}  __attribute__ ((packed)) BITMAPINFOHEADER;

static int isBMPFormat(PT_FileMap ptFileMap);
static int GetPixelDatasFrmBMP(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas);
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas);

/*bmp操作结构体*/
static T_PicFileParser g_tBMPParser = {
	.name           = "bmp",
	.isSupport      = isBMPFormat,
	.GetPixelDatas  = GetPixelDatasFrmBMP,
	.FreePixelDatas = FreePixelDatasForBMP,	
};

/**
 * @brief 判断文件是否是BMP
 * 
 * @param ptFileMap 映射后的文件
 * @return int 是：1;不是：0
 */
static int isBMPFormat(PT_FileMap ptFileMap)
{
    uint8_t *aFileHead = ptFileMap->pucFileMapMem;
    
	if (aFileHead[0] != 0x42 || aFileHead[1] != 0x4d)
		return 0;
	else
		return 1;
}

/**
 * @brief 将一行BMP数据转换为指定的RGB格式
 * 
 * @param iWidth 宽度
 * @param iSrcBpp BMP的BPP
 * @param iDstBpp 指定的BPP
 * @param pudSrcDatas BMP数据
 * @param pudDstDatas 转化后的数据
 * @return int 成功：0;失败：其他
 */
static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, uint8_t *pudSrcDatas, uint8_t *pudDstDatas)
{
	uint32_t dwRed;
	uint32_t dwGreen;
	uint32_t dwBlue;
	uint32_t dwColor;

	uint16_t *pwDstDatas16bpp = (uint16_t *)pudDstDatas;
	uint32_t   *pwDstDatas32bpp = (uint32_t *)pudDstDatas;

	int i;
	int pos = 0;

	if (iSrcBpp != 24)
	{
		return -1;
	}

	if (iDstBpp == 24)
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			dwBlue  = pudSrcDatas[pos++];
			dwGreen = pudSrcDatas[pos++];
			dwRed   = pudSrcDatas[pos++];
			if (iDstBpp == 32)
			{
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
				*pwDstDatas32bpp = dwColor;
				pwDstDatas32bpp++;
			}
			else if (iDstBpp == 16)
			{
				
				dwRed   = dwRed >> 3;
				dwGreen = dwGreen >> 2;
				dwBlue  = dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
				*pwDstDatas16bpp = dwColor;
				pwDstDatas16bpp++;
			}
		}
	}
	return 0;
}

/**
 * @brief 读取BMP文件
 * 
 * @param ptFileMap BMP文件
 * @param ptPixelDatas 读取的图像数据
 * @return int 成功：0;失败：其他
 */
static int GetPixelDatasFrmBMP(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
{
	BITMAPFILEHEADER *ptBITMAPFILEHEADER;
	BITMAPINFOHEADER *ptBITMAPINFOHEADER;

    uint8_t *aFileHead;

	int iWidth;
	int iHeight;
	int iBMPBpp;
	int y;

	uint8_t *pucSrc;
	uint8_t *pucDest;
	int iLineWidthAlign;
	int iLineWidthReal;

	/*获取文件相关信息*/
    aFileHead = ptFileMap->pucFileMapMem;

	ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;
	ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER));

	iWidth = ptBITMAPINFOHEADER->biWidth;
	iHeight = ptBITMAPINFOHEADER->biHeight;
	iBMPBpp = ptBITMAPINFOHEADER->biBitCount;

	if (iBMPBpp != 24)
	{
		DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"iBMPBpp = %d\n", iBMPBpp);
		DBG_PRINTF(DLOG_LVL_ERROR,DLOG_TAG,"sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER));
		return -1;
	}

	ptPixelDatas->iWidth  = iWidth;
	ptPixelDatas->iHeight = iHeight;
	
	ptPixelDatas->iLineBytes    = iWidth * ptPixelDatas->iBpp / 8;
    ptPixelDatas->iTotalBytes   = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes;
	ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes);
	if (NULL == ptPixelDatas->aucPixelDatas)
	{
		return -1;
	}

	iLineWidthReal = iWidth * iBMPBpp / 8;
	iLineWidthAlign = (iLineWidthReal + 3) & ~0x3;   
		
	pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits;
	pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign;

	pucDest = ptPixelDatas->aucPixelDatas;
	
	for (y = 0; y < iHeight; y++)
	{		
		
		CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest);
		pucSrc  -= iLineWidthAlign;
		pucDest += ptPixelDatas->iLineBytes;
	}
	return 0;	
}

/**
 * @brief 释放BMP数据
 * 
 * @param ptPixelDatas 数据
 */
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
	free(ptPixelDatas->aucPixelDatas);
	return 0;
}

/**
 * @brief 注册模块
 */
int BMPParserInit(void)
{
	return RegisterPicFileParser(&g_tBMPParser);
}

